﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Newtonsoft.Json.Linq;
using XDAFacebook;
using XFControls;
using XFControls.Utils;
using Timer = System.Windows.Forms.Timer;

namespace FBEntities.FBObjects
{
    public class FBNotificationListObject : IFBObject
    {
        public string id;
        public FBFrom from;
        public FBProxyPerson to;
        public DateTime created_time;
        public DateTime updated_time;
        public string title;
        public string message;
        public string link;
        public FBApplication application;
        public int unread;


        #region IFBObject Members

        public void Parse(JObject text)
        {
            FBParseUtilities.Parse(text, this);
        }

        #endregion

        public void MarkAsRead()
        {
            var wrapper = FBParseUtilities.MarkAsRead(id);
            wrapper.Post();
        }
    }

    public class FBNotificationObject
    {
        public List<long> EventRequests;
        public List<long> FriendRequests;
        public List<long> GroupRequests;
        public long MostRecentMessageId;

        public long MostRecentPokeId;

        public long MostRecentShareId;
        public int UnreadMessages;
        public int UnreadPokes;
        public int UnreadShares;

        public FBNotificationObject(JObject obj)
        {
            FriendRequests = new List<long>();
            GroupRequests = new List<long>();
            EventRequests = new List<long>();

            var msg = obj["messages"] as JObject;
            var pokes = obj["pokes"] as JObject;
            var shares = obj["shares"] as JObject;

            if (msg == null || pokes == null || shares == null)
                return;

            var fReq = obj["friend_requests"] as JArray;
            var gReq = obj["group_invites"] as JArray;
            var eReq = obj["event_invites"] as JArray;

            if (msg["unread"] != null)
                UnreadMessages = (int)msg["unread"];
            if (msg["most_recent"] != null)
                MostRecentMessageId = (long)msg["most_recent"];

            if (pokes["unread"] != null)
                UnreadPokes = (int)pokes["unread"];
            if (pokes["most_recent"] != null)
                MostRecentPokeId = (long)pokes["most_recent"];

            if (shares["unread"] != null)
                UnreadShares = (int)shares["unread"];
            if (shares["most_recent"] != null)
                MostRecentShareId = (long)shares["most_recent"];

            foreach (long id in fReq)
                FriendRequests.Add(id);
            foreach (long id in gReq)
                GroupRequests.Add(id);
            foreach (long id in eReq)
                EventRequests.Add(id);
        }

        public override bool Equals(object obj)
        {
            if (obj is FBNotificationObject)
            {
                var temp = obj as FBNotificationObject;

                return UnreadMessages == temp.UnreadMessages &&
                       UnreadPokes == temp.UnreadPokes &&
                       UnreadShares == temp.UnreadShares &&
                       FriendRequests.Count == temp.FriendRequests.Count &&
                       GroupRequests.Count == temp.GroupRequests.Count &&
                       EventRequests.Count == temp.EventRequests.Count;
            }
            return false;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

    public class FBNotifications : IUpdateable
    {
        private readonly string getListUrl = "https://graph." + Settings.Domain + ".com/me/notifications/?include_read=1&";
        private readonly string getUrl = "https://api." + Settings.Domain + ".com/method/notifications.get?format=JSON&";
        private List<FBNotificationListObject> _list;
        private FBNotificationObject _notification;

        private Timer _timer;
        private int time = 60000;

        public FBNotifications()
        {
            getUrl += FBParseUtilities.authKey;
            getListUrl += FBParseUtilities.authKey;

            _list = new List<FBNotificationListObject>();

            WaitCallback cbNote = updateNotification;
            WaitCallback cbList = updateList;

            ThreadPool.QueueUserWorkItem(cbNote);
            ThreadPool.QueueUserWorkItem(cbList);
        }

        #region IUpdateable Members

        public event EventHandler Updated;
        public bool Show { get; set; }

        public void StartUpdates()
        {
            if (_timer != null)
                _timer.Dispose();

            _timer = new Timer();
            _timer.Interval = time;
            _timer.Tick += (o, e) =>
                           {
                               WaitCallback cbNote = updateNotification;
                               WaitCallback cbList = updateList;

                               ThreadPool.QueueUserWorkItem(cbNote);
                               ThreadPool.QueueUserWorkItem(cbList);
                           };

            _timer.Enabled = true;
        }

        public int GetNumber()
        {
            return _list.Where(i => i.unread == 1).Count();
        }

        public void OnClick()
        {
            if (Clicked != null)
                Clicked(this, new EventArgs());
        }

        #endregion

        public event EventHandler Clicked;
        public event UpdateEventHandler ListUpdated;
        public event UpdateEventHandler NotificationUpdated;

        public List<FBNotificationListObject> GetNotificationList()
        {
            return _list.OrderByDescending(i => i.unread).ThenByDescending(i => i.updated_time).ToList();
        }

        public FBNotificationObject GetNotifictaions()
        {
            return _notification;
        }

        public void ManualUpdate()
        {
            updateList(null);
            updateNotification(null);
        }

        private void updateList(object val)
        {
            var wrapper = new WebDownloaderWrapper(getListUrl);
            string json = wrapper.Download();

            if (string.IsNullOrEmpty(json)) return;

            Parse(json);
        }

        public void Parse(string json)
        {
            JObject o = JObject.Parse(json);

            var array = o["data"] as JArray;
            var temp = new List<FBNotificationListObject>();

            if (array == null) return;

            foreach (JToken t in array)
            {
                if (t.Type == JTokenType.Null)
                    continue;

                var itm = new FBNotificationListObject();
                itm.Parse(t as JObject);
                temp.Add(itm);
            }

            int listCount = _list.Where(i => i.unread == 1).Count();
            int tempCount = temp.Where(i => i.unread == 1).Count();

            if (listCount == tempCount) return;

            Show = listCount < tempCount;
            _list = temp;
            if (ListUpdated != null)
                ListUpdated(this, new EventArgs());

            if (Updated != null)
                Updated(this, new EventArgs());
        }

        private void updateNotification(object val)
        {
            var wrapper = new WebDownloaderWrapper(getUrl);
            string json = wrapper.Download();

            if (!string.IsNullOrEmpty(json))
            {
                JObject o = JObject.Parse(json);
                var temp = new FBNotificationObject(o);

                if (_notification == null || !_notification.Equals(temp))
                {
                    _notification = temp;
                    if (NotificationUpdated != null)
                        NotificationUpdated(this, new EventArgs());

                    if (Updated != null)
                        Updated(this, new EventArgs());
                }
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (_timer != null)
                _timer.Dispose();

            Updated = null;
            Clicked = null;
            ListUpdated = null;
            NotificationUpdated = null;
        }

        #endregion
    }
}

/*
 List object:
 * 
 *{
    "notifications": [
    {
      "notification_id": "########",
      "sender_id": ########,
      "recipient_id": ########,
      "created_time": ########,
      "updated_time": ########,
      "title_html": "Html",
      "title_text": "Not Html",
      "body_html": "Html",
      "body_text": "Not Html",
      "href": "http://www.facebook.com/stuff",
      "app_id": ########,
      "is_unread": 0,
      "is_hidden": 0,
      "object_id": "########_########",
      "object_type": "stream"
    },

 * 
 Get Object:
 * 
 * {
  "messages": {
    "unread": 0,
    "most_recent": ########
  },
  "pokes": {
    "unread": 1,
    "most_recent": ########
  },
  "shares": {
    "unread": 0,
    "most_recent": 0
  },
  "friend_requests": [],
  "group_invites": [
    ########,
    ########,
    ########,
    ########,
    ########
  ],
  "event_invites": [
    ########,
    ########,
    ########,
    ########
  ]
}
 
 
 */